#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <X11/X.h>
#include <X11/keysymdef.h>
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>

Display* dpy;
Window root;
GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
XVisualInfo* vi;
Colormap cmap;
XSetWindowAttributes swa;
Window win;
GLXContext glc;
XWindowAttributes gwa;
XEvent xev;

void DrawPrepare() {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
};

void DrawDotGreen(float x, float y, float size) {
	glBegin(GL_QUADS);
	glColor3f(0.0, 1.0, 0.0); glVertex3f(x, y, 0.0);
	glColor3f(0.0, 1.0, 0.0); glVertex3f(x+size, y, 0.0);
	glColor3f(0.0, 1.0, 0.0); glVertex3f(x+size, y+size, 0.0);
	glColor3f(0.0, 1.0, 0.0); glVertex3f(x, y+size, 0.0);
	glEnd();
};

void DrawDotRed(float x, float y, float size) {
	glBegin(GL_QUADS);
	glColor3f(1.0, 0.0, 0.0); glVertex3f(x, y, 0.0);
	glColor3f(1.0, 0.0, 0.0); glVertex3f(x+size, y, 0.0);
	glColor3f(1.0, 0.0, 0.0); glVertex3f(x+size, y+size, 0.0);
	glColor3f(1.0, 0.0, 0.0); glVertex3f(x, y+size, 0.0);
	glEnd();
};

void DrawLineRed(double k, double b, double size) {
  for(double x=-1.0f; x<1.0f; x+=0.01f)
    DrawDotRed(x, k*x+b, size);
};

void DrawLineRed2(double a, double b, double c, double size) {
  for(double x=-1.0f; x<1.0f; x+=0.01f)
    DrawDotRed(x, a*x*x + b*x + c, size);
};


typedef struct {
  double x;
  double y;
} Pair;

int main() {

  srand(time(NULL));

  dpy = XOpenDisplay(NULL);
	if(dpy == NULL) {
		printf("\n\tCannot connect to X server\n\n");
		exit(0);
	};

	root = DefaultRootWindow(dpy);
	vi = glXChooseVisual(dpy, 0, att);
	if(vi == NULL) {
		printf("\n\tno appropriate visual found\n\n");
		exit(0);
	} else {
		printf("\n\tvisual %p selected\n", (void*)vi->visualid);
	};

	cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
	swa.colormap = cmap;
	swa.event_mask = KeyPressMask;
	win = XCreateWindow(dpy, root, 0, 0, 600, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
	XMapWindow(dpy, win);
	XStoreName(dpy, win, "OpenGL and X");
	glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
	glXMakeCurrent(dpy, win, glc);

	glEnable(GL_DEPTH_TEST);

  unsigned int count_of_pairs = 4;
  Pair pairs[count_of_pairs];

  for(int i=0; i<count_of_pairs; i++) {
    pairs[i].x = (double)(rand() % 1000) / 1001.0f - 0.5f;
    pairs[i].y = (double)(rand() % 1000) / 1001.0f - 0.5f;
  };

  double a = ((double)(rand() % 1000)) / 1001.0f;
  double b = ((double)(rand() % 1000)) / 1001.0f;
  double c = ((double)(rand() % 1000)) / 1001.0f;

  double da = 0;
  double db = 0;
  double dc = 0;
  double alpha = 0.9f;
  double betha = 0.7f;


	while(1) {
		if(XCheckTypedWindowEvent(dpy, win, KeyPress, &xev)) {
			KeySym sym = XLookupKeysym(&xev.xkey, 0);
      switch(sym) {
        default:
					glXMakeCurrent(dpy, None, NULL);
					glXDestroyContext(dpy, glc);
					XDestroyWindow(dpy, win);
					XCloseDisplay(dpy);
					exit(0);
					break;
      };
    };

		XGetWindowAttributes(dpy, win, &gwa);

    // Old part ----------------------------------------

    DrawPrepare();

    for(int i=0; i<count_of_pairs; i++) {
        DrawDotGreen(pairs[i].x, pairs[i].y, 0.01f);
        da = alpha*da - betha*(a*pairs[i].x*pairs[i].x + b*pairs[i].x + c - pairs[i].y)*pairs[i].x*pairs[i].x;
        db = alpha*db - betha*(a*pairs[i].x*pairs[i].x + b*pairs[i].x + c - pairs[i].y)*pairs[i].x;
        dc = alpha*dc - betha*(a*pairs[i].x*pairs[i].x + b*pairs[i].x + c - pairs[i].y);
        a += da;
        b += db;
        c += dc;
    };

    //DrawLineRed(k, b, 0.01f);
    DrawLineRed2(a, b, c, 0.01f);

    glViewport(0, 0, gwa.width, gwa.height);
    glXSwapBuffers(dpy, win);

  };



  return 0;
};
